package com.ms.education.ucenter.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ms.education.JwtUtils;
import com.ms.education.MD5Util;
import com.ms.education.R;
import com.ms.education.constant.MsmCodeConstant;
import com.ms.education.constant.RoleConstant;
import com.ms.education.exceptionHandler.EduException;
import com.ms.education.ucenter.entity.User;
import com.ms.education.ucenter.entity.vo.RegisterByPhoneVo;
import com.ms.education.ucenter.mapper.UserMapper;
import com.ms.education.ucenter.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ms.education.ucenter.service.feign.AclFeignService;
import com.ms.education.ucenter.service.feign.CourseFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 该表为普通用户，可以访问前台界面 服务实现类
 * </p>
 *
 * @author ms
 * @since 2023-01-12
 */
@Service
public class UserServiceImp extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private AclFeignService aclFeignService;

    @Autowired
    private CourseFeignService courseFeignService;

    @Override
    public R pageUser(User user, long current, long limit) {
        String nickname = user.getNickname();
        Integer sex = user.getSex();
        Integer lowAge = user.getLowAge();
        Integer highAge = user.getHighAge();
        Date beginTime = user.getBeginTime();
        Date endTime = user.getEndTime();
        Page<User> page = new Page<>();
        page.setCurrent(current).setSize(limit);
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(nickname)) {
            wrapper.like("nickname", nickname);
        }
        if (!StringUtils.isEmpty(sex)) {
            wrapper.eq("sex", sex);
        }
        if (!StringUtils.isEmpty(lowAge)) {
            wrapper.ge("age", lowAge);
        }
        if (!StringUtils.isEmpty(highAge)) {
            wrapper.le("age", highAge);
        }
        if (!StringUtils.isEmpty(beginTime)) {
            wrapper.ge("gmt_create", beginTime);
        }
        if (!StringUtils.isEmpty(endTime)) {
            wrapper.le("gmt_create", endTime);
        }
        wrapper.orderByDesc("gmt_modified");
        this.page(page, wrapper);
        long rows = page.getTotal();
        List<User> users = page.getRecords();
        users.forEach(u -> u.setIsLogin(StpUtil.getSessionByLoginId(u.getId(), false) != null));
        return R.ok().data("rows", rows).data("users", users);
    }

    @Override
    public Integer countRegisterDay(String day) {
        return baseMapper.countRegisterDay(day);
    }

    @Override
    public void registerByPhone(RegisterByPhoneVo register) {
        String phone = MD5Util.getMD5(register.getMobile());
        String code = redisTemplate.opsForValue().get(MsmCodeConstant.MSM_CACHE_CODE + phone);
        if (StringUtils.isEmpty(code)) {
            throw new EduException(20001, "验证码已失效");
        }
        if (!MD5Util.getMD5(register.getCode()).equals(code)) {
            throw new EduException(20001, "验证码错误");
        }
        QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("mobile", register.getMobile());
        long count = count(wrapper);
        if (count != 0) {
            throw new EduException(20001, "该手机号已被注册");
        }
        User user = new User();
        user.setNickname(register.getNickname());
        user.setPassword(MD5Util.getMD5(register.getPassword()));
        user.setMobile(register.getMobile());
        save(user);
        //为用户赋予前台用户的角色
        aclFeignService.endowedUserRole(user.getId(), new Integer[]{RoleConstant.USER_ROLE_ID});
    }

    @Override
    public String loginByPhone(User user) {
        String mobile = user.getMobile();
        QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("mobile", mobile);
        User u = getOne(wrapper);
        if (u == null) {
            throw new EduException(20001, "您还未注册！");
        }
        if (!MD5Util.getMD5(user.getPassword()).equals(u.getPassword())) {
            throw new EduException(20001, "密码错误！");
        }
        if (u.getIsDisabled()) {
            throw new EduException(20001, "账号被封禁");
        }
        StpUtil.login(u.getId()); //使用Sa-Token登录会话
        return StpUtil.getTokenInfo().getTokenValue(); //返回token令牌
    }

    @Override
    public User getUserByOpenId(String openid) {
        QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("open_id", openid);
        return getOne(wrapper);
    }

    @Override
    public String loginByCode(User user) {
        String mobile = user.getMobile();
        String code = user.getCode();
        String c = redisTemplate.opsForValue().get(MsmCodeConstant.MSM_CACHE_CODE + MD5Util.getMD5(mobile));
        if (StringUtils.isEmpty(c)) {
            throw new EduException(20001, "验证码已失效");
        }
        if (!c.equals(MD5Util.getMD5(code))) {
            throw new EduException(20001, "验证码错误");
        }
        QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("mobile", mobile);
        user = getOne(wrapper);
        if (user == null) {
            throw new EduException(20001, "您还未注册！");
        }
        if (user.getIsDeleted()) {
            throw new EduException(20001, "账号被封禁");
        }
        StpUtil.login(user.getId());
        return StpUtil.getTokenInfo().getTokenValue();
    }

    @Override
    public void updatePassword(String mobile, String newPassword, String code) {
        String c = redisTemplate.opsForValue().get(MsmCodeConstant.MSM_CACHE_CODE + MD5Util.getMD5(mobile));
        if (StringUtils.isEmpty(c)) {
            throw new EduException(20001, "验证码已过期");
        }
        if (!c.equals(MD5Util.getMD5(code))) {
            throw new EduException(20001, "验证码错误");
        }
        User user = getOne(new QueryWrapper<User>().eq("mobile", mobile));
        if (user == null) {
            throw new EduException(20001, "该手机号并未注册");
        }
        if (MD5Util.getMD5(newPassword).equals(user.getPassword())) {
            throw new EduException(20001, "新密不能与旧密码相同");
        }
        user.setPassword(MD5Util.getMD5(newPassword));
        updateById(user);
    }

    @Override
    public User getUserByMobile(String mobile) {
        QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("mobile", mobile);
        return getOne(wrapper);
    }

    @Override
    public Map<String, Object> getUserInfo(int userId) {
        User user = getById(userId);
        if (user == null) {
            throw new EduException(20001, "用户不存在");
        }
        HashMap<String, Object> res = new HashMap<>();
        res.put("name", user.getNickname());
        res.put("avatar", user.getAvatar());
        res.put("teacherId", user.getTeacherId());
        Map<String, Object> data = aclFeignService.getRoleAndPermission(userId).getData();
        res.put("roles", data.get("roles"));
        res.put("permissionValueList", data.get("permissionValueList"));
        return res;
    }

    @Override
    public Page<User> pageClassUser(Integer classId, long current, long limit, String name) {
        Page<User> page = new Page<>(current, limit);
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(name)) {
            wrapper.like("nickname", name);
        }
        List<Integer> userIds = courseFeignService.getClassUserIds(classId);
        if (userIds.isEmpty()) {
            return page;
        } else {
            wrapper.in("id", userIds);
            return page(page, wrapper);
        }
    }

    @Override
    public void untieOrDisableUser(Integer userId, boolean flag) {
        User user = new User();
        user.setId(userId);
        user.setIsDisabled(flag);
        updateById(user);
        if (flag) {
            StpUtil.disable(userId, -1);
        } else {
            StpUtil.untieDisable(userId);
        }
    }
}


